package com.xbongbong.saas.analytical.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.FormDataHelp;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.enums.errorcodes.PurchaseErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.RefundErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.ReturnedPurchaseErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.formdata.pojo.SaasNeedRedundantAttrPojo;
import com.xbongbong.saas.analytical.SaasValidateAnalyticalService;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.BusinessProductEntity;
import com.xbongbong.saas.domain.entity.ext.PurchaseEntityExt;
import com.xbongbong.saas.enums.InstockTypeEnum;
import com.xbongbong.saas.enums.OutstockTypeEnum;
import com.xbongbong.saas.enums.SelectProductEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.OutstockEnum;
import com.xbongbong.saas.enums.business.PurchaseEnum;
import com.xbongbong.saas.enums.business.ReturnedPurchaseEnum;
import com.xbongbong.saas.enums.dictionary.ReturnedStatusEnum;
import com.xbongbong.saas.help.AnalyticalHelp;
import com.xbongbong.saas.help.SaasProductHelp;
import com.xbongbong.saas.help.SaveFormatHelp;
import com.xbongbong.saas.model.OutstockProductModel;
import com.xbongbong.saas.model.PurchaseModel;
import com.xbongbong.saas.model.PurchaseProductModel;
import com.xbongbong.saas.service.toolbox.help.UserTeamHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.util.ProductUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleOrDefaultFromFormData;
import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getIntegerOrDefaultFromFormData;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author 吴峰
 * @date 2021/07/15 17:15
 */
@Service("returnedPurchaseAnalyticalServiceImpl")
public class ReturnedPurchaseValidateAnalyticalServiceImpl implements SaasValidateAnalyticalService {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(ReturnedPurchaseValidateAnalyticalServiceImpl.class);
    
    @Resource
    private EsHelper esHelper;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private PurchaseModel purchaseModel;
    @Resource
    private FormDataHelp formDataHelp;
    @Resource
    private PurchaseProductModel purchaseProductModel;
    @Resource
    private OutstockProductModel outstockProductModel;
    @Resource
    private SaasProductHelp saasProductHelp;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private UserTeamHelp userTeamHelp;
    @Resource
    private AnalyticalHelp analyticalHelp;

    @Override
    public List<Integer> type() {
        return Arrays.asList(XbbRefTypeEnum.RETURNED_PURCHASE.getCode());
    }

    @Override
    public void analyticalData(ValidateDataDTO validateDataDTO) throws XbbException {
        beforeSave(validateDataDTO);
        //没有负责团队的 单负责人
        userTeamHelp.checkPermissionOptionTeam(validateDataDTO);
    }
    
    public void beforeSave(ValidateDataDTO validateDataDTO) throws XbbException {
        try {
            String corpid = validateDataDTO.getCorpid();
            JSONObject data = validateDataDTO.getData();
            Map<String, FieldAttrEntity> explainMap = validateDataDTO.getExplainMap();
            // 选择关联采购合同
            SaveFormatHelp.formatLinkBusiness4Save(data, ReturnedPurchaseEnum.PURCHASE_SHEET_ID.getAttr(), ReturnedPurchaseEnum.PURCHASE_SHEET_ID_LINKED_TEXT.getAttr(), ReturnedPurchaseEnum.PURCHASE_SHEET_ID.getFieldType());
            SaveFormatHelp.formatLinkBusiness4Save(data, ReturnedPurchaseEnum.LINK_SUPPLIER.getAttr(), ReturnedPurchaseEnum.LINK_SUPPLIER_HIDE.getAttr(), ReturnedPurchaseEnum.LINK_SUPPLIER.getFieldType());
            validateDataDTO.setData(data);
            // 保存前参数格合理化校验
            parameterCheck(validateDataDTO);
            //保存前序列号必填校验
            SaveFormatHelp.batchSaveRequiredCheck(validateDataDTO);
            // 冗余相关数据信息
            redundantDataProcessing(validateDataDTO);
            Long dataId = validateDataDTO.getDataId();
            Long taskId = validateDataDTO.getTaskId();
            boolean isNew = analyticalHelp.isNew(validateDataDTO.getDataId(), taskId, validateDataDTO.getCorpid());
            Long purchaseId;
            JSONArray jsonArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(data,ReturnedPurchaseEnum.PRODUCTS.getAttr(),new JSONArray());
            if (Objects.isNull(dataId) || Objects.equals(dataId, 0L)) {
                purchaseId = getPurchaseSheetId(data);
                PaasFormDataEntityExt purchaseFormData = formDataHelp.getFormData(purchaseId, corpid, XbbRefTypeEnum.PURCHASE.getCode());
                if (Objects.nonNull(purchaseFormData)) {
                    Integer returnPurchaseId = getIntegerOrDefaultFromFormData(purchaseFormData.getData(), PurchaseEnum.RETURNED_PURCHASE_ID.getAttr(), 0);
                    if (Objects.nonNull(returnPurchaseId) && returnPurchaseId > 1) {
                        throw new XbbException(ReturnedPurchaseErrorCodeEnum.API_ERROR_230020);
                    }
                }
                // 导入需要写入退货单价和单价小计字段
                if (Objects.equals(validateDataDTO.getIsImport(), 1)) {
                    List<BusinessProductEntity> productEntityList = purchaseProductModel.getPurchasePrice(purchaseId, corpid);
                    Map<Long, Double> priceMap = new HashMap<>(productEntityList.size());
                    productEntityList.forEach(item -> priceMap.put(item.getProductId(), item.getCost()));
                    if (Objects.nonNull(jsonArray)) {
                        for (int i = 0; i < jsonArray.size(); i++) {
                            JSONObject jsonObject = jsonArray.getJSONObject(i);
                            Long productId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
                            if (priceMap.containsKey(productId)) {
                                Double num = jsonObject.getDouble(SelectProductEnum.NUM.getAttr());
                                jsonObject.put(SelectProductEnum.COST.getAttr(), priceMap.get(productId));
                                jsonObject.put(SelectProductEnum.SUBTOTAL.getAttr(), Arith.mul(priceMap.get(productId), num));
                            }
                        }
                    }
                }
            } else {
                purchaseId = FastJsonHelper.getLongOrDefaultFromFormData(data, ReturnedPurchaseEnum.PURCHASE_SHEET_ID.getAttr(), 0L);
            }

            Boolean productCanSee = true;
            boolean allOutBound;
//        boolean hasOut = Objects.isNull(FastJsonHelper.getLongOrDefaultFromFormData(validateDataDTO.getData(),ReturnedPurchaseEnum.OUTSTOCK_ID.getAttr(),null));
            if (!isNew) {
                productCanSee = commonHelp.attrCanSee(validateDataDTO.getExplainMap().get(ReturnedPurchaseEnum.PRODUCTS.getAttr()),validateDataDTO.getDataId(),validateDataDTO.getCreatorId(),validateDataDTO.getLoginUser(),validateDataDTO.getCorpid(),XbbRefTypeEnum.RETURNED_PURCHASE.getCode());
            }
            if (isNew) {
                validateDataProduct(jsonArray, corpid, isNew,purchaseId, dataId);
                data.put(ReturnedPurchaseEnum.RETURNED_STATUS.getAttr(), ReturnedStatusEnum.UNRETURNED.getCode());
            } else {
                productCanSee = commonHelp.attrCanSee(explainMap.get(ReturnedPurchaseEnum.PRODUCTS.getAttr()),dataId,validateDataDTO.getCreatorId(),validateDataDTO.getLoginUser(),corpid,XbbRefTypeEnum.RETURNED_PURCHASE.getCode());
                if (productCanSee) {
                    // 关联产品字段启用，可见，及高级可见时才校验关联产品
                    allOutBound = validateDataProduct(jsonArray, corpid, isNew,purchaseId, dataId);
                } else {
                    // 不可见就取是否出库完毕原值
                    Integer outBound = getIntegerOrDefaultFromFormData(data, ReturnedPurchaseEnum.OUTSTOCK_ID.getAttr(), BasicConstant.ONE);
                    allOutBound = outBound != 0;
                }
                data.put(ReturnedPurchaseEnum.OUTSTOCK_ID.getAttr(), allOutBound ? 1 : "");
                //编辑和新建和编辑进审批时完全分开
                PaasFormDataEntity paasFormDataEntity = validateDataDTO.getPaasFormDataEntity();
                //编辑进审批时，已经走过一遍beforesave了，无需在设置退货状态值
                if (Objects.nonNull(paasFormDataEntity)) {
                    JSONObject oldData = paasFormDataEntity.getData();
                    String returnedStatus = FastJsonHelper.getStringOrDefaultFromFormData(oldData, PurchaseEnum.RECEIVE_STATUS.getAttr(), ReturnedStatusEnum.UNRETURNED.getCode());
                    if (!Objects.equals(returnedStatus,ReturnedStatusEnum.CLOSED.getCode())) {
                        if (jsonArray.isEmpty()) {
                            data.put(ReturnedPurchaseEnum.RETURNED_STATUS.getAttr(),ReturnedStatusEnum.UNRETURNED.getCode());
                        }else if (allOutBound){
                            data.put(ReturnedPurchaseEnum.RETURNED_STATUS.getAttr(),ReturnedStatusEnum.RETURNED.getCode());
                        }else if (!Objects.equals(returnedStatus,ReturnedStatusEnum.DELIVERED.getCode())){
                            data.put(ReturnedPurchaseEnum.RETURNED_STATUS.getAttr(),ReturnedStatusEnum.UNRETURNED.getCode());
                        }
                    }
                }
            }

            Map<String,Boolean> attrCanSeeMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            attrCanSeeMap.put(ReturnedPurchaseEnum.PRODUCTS.getAttr(),productCanSee);
            SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo = new SaasNeedRedundantAttrPojo();
            saasNeedRedundantAttrPojo.setAttrCanSeeMap(attrCanSeeMap);
            validateDataDTO.setSaasNeedRedundantAttrPoJo(saasNeedRedundantAttrPojo);

            Double returnedPurchaseAmount = getDoubleOrDefaultFromFormData(data, ReturnedPurchaseEnum.RETURNED_PURCHASE_AMOUNT.getAttr(), 0D);
            Double returnAmount = getDoubleOrDefaultFromFormData(data, ReturnedPurchaseEnum.TOTAL_MONEY.getAttr(), 0D);
            //合计退款金额校验
            refundAmountJudgement(corpid, returnedPurchaseAmount, returnAmount, purchaseId, validateDataDTO.getSerialNo());
        } catch (XbbException e) {
            throw e;
        }  catch (Exception e) {
            LOGGER.error("returnedPurchaseAnalyticalServiceImpl.beforeSave error", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }


    /**
     * 合计退款金额金额校验
     *
     * @param corpid                 公司ID
     * @param returnedPurchaseAmount 合计退款金额
     * @param returnAmount           退货金额
     * @param purchaseId             采购合同ID
     * @param serialNo               编号
     * @throws XbbException error
     * @author zhouwq
     * @date 2020/2/19 14:47
     */
    private void refundAmountJudgement(String corpid, Double returnedPurchaseAmount, Double returnAmount, Long purchaseId, String serialNo) throws XbbException {
        if (returnedPurchaseAmount < BasicConstant.ZERO) {
            throw new XbbException(RefundErrorCodeEnum.API_ERROR_215022);
        }
        if (returnAmount < BasicConstant.ZERO) {
            throw new XbbException(RefundErrorCodeEnum.API_ERROR_215023);
        }
        if (returnedPurchaseAmount > returnAmount) {
            throw new XbbException(RefundErrorCodeEnum.API_ERROR_215020);
        }
        PurchaseEntityExt purchaseEntityExt = purchaseModel.getByKey(purchaseId, corpid);
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(ParameterConstant.CORPID, corpid);
        param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        param.put(ParameterConstant.FLOW_STATUS_IN, Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.PASS.getType(), FlowStatusEnum.IN_APPROVAL.getType()));
        List<PaasFormDataEntityExt> paasFormDataEntityExts = paasEsModel.selectByOneCondition(XbbRefTypeEnum.RETURNED_PURCHASE.getCode(), ReturnedPurchaseEnum.PURCHASE_SHEET_ID.getAttr(), purchaseId, param, IndexTypeEnum.IDX_SAAS_RETURNED_PURCHASE);
        //退货金额合计
        double returnAmountSum = returnAmount;
        for (PaasFormDataEntityExt returnedPurchaseEntity : paasFormDataEntityExts) {
            if (!Objects.equals(serialNo, returnedPurchaseEntity.getSerialNo())) {
                returnAmountSum = Arith.add(BasicConstant.ZERO_DOUBLE, getDoubleOrDefaultFromFormData(returnedPurchaseEntity.getData(), ReturnedPurchaseEnum.TOTAL_MONEY.getAttr(), BasicConstant.ZERO_DOUBLE));
            }
        }
        Double contractAmount = getDoubleOrDefaultFromFormData(purchaseEntityExt.getData(), ReturnedPurchaseEnum.TOTAL_MONEY.getAttr(), BasicConstant.ZERO_DOUBLE);
        if (Arith.sub(contractAmount, returnAmountSum) < BasicConstant.ZERO) {
            throw new XbbException(RefundErrorCodeEnum.API_ERROR_215005);
        }
    }

    private boolean validateDataProduct(JSONArray jsonArray, String corpid, boolean isNew, Long purchaseId, Long dataId) throws XbbException {
        boolean allbound = false;
        if (jsonArray.isEmpty()) {
            throw new XbbException(ReturnedPurchaseErrorCodeEnum.API_ERROR_230013);
        }
        Set<Long> pageProductIds = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String,Double> productNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        boolean needMerge = false;
        for (Object object:jsonArray) {
            JSONObject jsonObject = (JSONObject) object;
            if (Objects.isNull(jsonObject.getLong(BusinessConstant.REF_PRODUCT_ID))) {
                needMerge = true;
                break;
            }
        }
        Map<String,Double> productNumMap2 = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (Object object:jsonArray) {
            JSONObject jsonObject = (JSONObject) object;
            Long productId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
            pageProductIds.add(productId);
            Long refProductId = jsonObject.getLong(BusinessConstant.REF_PRODUCT_ID);
            Long subProductId = jsonObject.getLong(BusinessConstant.PRODUCT_SUB_ID);
            Double productNum = jsonObject.getDouble(SelectProductEnum.NUM.getAttr());
            if (Objects.nonNull(subProductId)) {
                String key = productId + "_" + subProductId;
                Double num = productNumMap2.getOrDefault(key,0D);
                num += productNum;
                productNumMap2.put(key,num);
            }
            String key;
            if (needMerge) {
                key = productId.toString();
            } else {
                key = productId + "_" + refProductId;
            }
            Double num = productNumMap.getOrDefault(key,0D);
            num += productNum;
            productNumMap.put(key,num);
        }
        Map<Long,String> pageProductMap = saasProductHelp.productExit(corpid,new ArrayList<>(pageProductIds));
        // 不能大于采购入库数量
        Map<String,Double> businessProductMap = saasProductHelp.getPurchaseInstockProduct(corpid,purchaseId, InstockTypeEnum.PURCHASE_INSTOCK.getCode(), needMerge, dataId);
        ProductUtil.upstreamDocumentsProductNumLegalCheck(false, productNumMap,businessProductMap,pageProductMap, I18nMessageUtil.getMessage(I18nStringConstant.MORE_THAN_PURCHASE_STOCH_NUM));

        if (!isNew){
            //编辑不能少于退货已出库值
            BoolQueryBuilder boolQueryBuilder = boolQuery();
            boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
            boolQueryBuilder.filter(termQuery(OutstockEnum.getEsAttr4Keyword(OutstockEnum.TYPE), OutstockTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode()));
            boolQueryBuilder.filter(termsQuery(OutstockEnum.getEsAttr4Keyword(OutstockEnum.REF_ID), Collections.singletonList(dataId)));
            boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
            List<PaasFormDataEntity> paasFormDataEntityList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_OUTSTOCK,boolQueryBuilder,PaasFormDataEntity.class,Collections.singletonList(FieldTypeEnum.DATAID.getAlias()));
            List<Long> outstockIdList = new ArrayList<>();
            paasFormDataEntityList.forEach(item -> outstockIdList.add(item.getDataId()));
            Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("del", 0);
            param.put("outstockIdIn", outstockIdList);
            List<BusinessProductEntity> outstockProductEntityList = outstockProductModel.findProductNum(param);
            Map<String,Double> returnProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (BusinessProductEntity entity : outstockProductEntityList){
                String key = entity.getProductId() + "_" + entity.getRefProductId();
                Double num  = returnProductMap.getOrDefault(key,0D);
                if (!pageProductMap.containsKey(entity.getProductId())) {
                    pageProductMap.put(entity.getProductId(), entity.getProductName());
                }
                num += entity.getProductNum();
                returnProductMap.put(key,num);
            }
            allbound = ProductUtil.upstreamDocumentsProductNumLegalCheck(false, returnProductMap, productNumMap2,pageProductMap,I18nMessageUtil.getMessage(I18nStringConstant.LESS_THAN_PURCHASE_REFUND_NUM));
        }
        return allbound;
    }
    /**
     * 采购退货单参数保存前对相关参数进行合理化校验
     *
     * @param validateDataDTO 前端传参数据
     * @throws XbbException 参数不符合要求错误提醒
     * @author Jian.Wang
     * @date 2019/2/21 10:04
     * @since v1.0
     */
    private void parameterCheck(ValidateDataDTO validateDataDTO) throws XbbException {
        JSONObject data = validateDataDTO.getData();
        if (data == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
        }
    }
    /**
     * 采购退货单根据传入参数将冗余数据存入data中，方便使用时获取
     *
     * @param validateDataDTO 前端传参数据
     * @throws XbbException 参数不符合要求错误提醒
     * @author Jian.Wang
     * @date 2019/2/21 10:04
     * @since v1.0
     */
    private void redundantDataProcessing(ValidateDataDTO validateDataDTO) throws XbbException{
        String corpid = validateDataDTO.getCorpid();
        JSONObject data = validateDataDTO.getData();
        if (data == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
        }
        // 获取到采购合同的ID
        Long purchaseId = getPurchaseSheetId(data);
        PurchaseEntityExt purchaseEntityExt = purchaseModel.getByKey(purchaseId, corpid);
        if (null == purchaseEntityExt) {
            throw new XbbException(PurchaseErrorCodeEnum.API_ERROR_225025);
        }
        JSONObject dataList = purchaseEntityExt.getData();
        Long supplierId = dataList.getLong(PurchaseEnum.SUPPLIER_ID.getAttr());
        data.put(ReturnedPurchaseEnum.SUPPLIER_ID.getAttr(),supplierId);
        validateDataDTO.setData(data);
    }
    /**
     * 获取采购合同ID
     *
     * @param data 数据源
     * @return Long 采购合同ID
     * @author Jian.Wang
     */
    private Long getPurchaseSheetId(JSONObject data) throws XbbException {
        if (null == data) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
        }
        Long purchaseId = FastJsonHelper.getLongFromFormData(data, ReturnedPurchaseEnum.PURCHASE_SHEET_ID.getAttr());
        if (null == purchaseId) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
        }
        return purchaseId;
    }
}
